package com.caishi.lkx.exam.api;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.caishi.lkx.common.AdminBaseApi;
import com.caishi.lkx.common.role.Role;
import com.caishi.lkx.common.role.Roles;
import com.caishi.lkx.common.util.ConvertUtil;
import com.caishi.lkx.exam.QuestionCollectionBlockItem;
import com.caishi.lkx.exam.ienum.type.*;
import com.caishi.lkx.exam.model.*;
import com.caishi.lkx.exam.service.*;
import com.caishi.lkx.exam.util.WordToHtmlInOrder;
import com.caishi.lkx.exam.vo.SpecialConditionVo;
import com.zzw.common.Wrappers;
import com.zzw.common.annotation.RateLimiterApi;
import com.zzw.common.annotation.ResultIgnore;
import com.zzw.common.entity.impl.BSIntEntity;
import com.zzw.common.entity.impl.BaseEntity;
import com.zzw.common.exception.BizException;
import com.zzw.common.exception.BizRuntimeException;

import com.caishi.lkx.exam.model.re.ExColumnConfigReModel;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author by Jansia
 * @Date 2022/1/20 16:27
 * @Description 试卷Api
 */
@Tag(name = "试卷相关接口")
@Slf4j
@RestController
@RequestMapping("/exam/paper")
public class PaperApi extends AdminBaseApi<IPaperService, PaperModel, String> {
    @Resource
    private IPaperService service;
    @Autowired
    private WordToHtmlInOrder wordToHtmlInOrder;

    @Resource
    private ICategoryService categoryService;

    @Resource
    private IExColumnConfigReService exColumnConfigReService;
    @Resource
    private IChapterService chapterService;
    @Resource
    private IPaperRecordsService paperRecordsService;
    //    @Resource
//    private EsSearchUtil<PaperModel, String, IPaperService> esSearchUtil;
    @Resource
    private IExamService examService;
    //    @Resource
//    private PaperEsService paperEsService;
    @Resource
    private IIndustryService industryService;

    @Resource
    private IColumnService columnService;
    @Resource
    private IQuestionService questionService;

    @Resource
    private IQuestionTypeService questionTypeService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public IPaperService loadService() {
        return service;
    }

    @GetMapping("/detail")
    @Operation(summary = "查看试卷详情")
    @Parameters({
            @Parameter(name = "id", description = "id", required = true),
    })
    @Roles
    public PaperModel getPaper(@RequestParam String id) {
        PaperModel paperInfo = service.getPaperInfo(id);
        if (null == paperInfo) {
            return null;
        }
        CategoryModel categoryModel = categoryService.getById(paperInfo.getCategoryId());
        paperInfo.setCategoryName(categoryModel.getName());
        paperInfo.setExamId(categoryModel.getExamId());
        paperInfo.setExamName(examService.queryName(categoryModel.getExamId()));
        paperInfo.setIndustryId(categoryModel.getIndustryId());
        paperInfo.setIndustryName(industryService.queryName(categoryModel.getIndustryId()));
        return paperInfo;
    }

    @GetMapping("/paperChapterUnused")
    @Operation(summary = "科目下章节未使用的试卷")
    public Page<PaperModel> paperChapterUnused(Page<PaperModel> page, Long categoryId, String keyword) {
        return service.paperChapterUnused(page, categoryId, keyword);
    }

    @Override
    @GetMapping("/page")
    @Roles({Role.admin})
    public IPage<PaperModel> page(@ModelAttribute Page<PaperModel> page, @ModelAttribute PaperModel model, @NotNull JSONObject otherParam) {
        LambdaQueryWrapper<PaperModel> wrapper = baseWrapper(model, otherParam);
        IPage<PaperModel> data = loadService().page(model.getCategoryId() == null ? page : service.pageProcessing(page), wrapper);
        data.getRecords().parallelStream().forEach(v -> {
            v.setCategoryName(categoryService.queryName(v.getCategoryId()));
            if (v.getOldCategoryId() != null) {
                v.setOldCategoryName(categoryService.queryName(v.getOldCategoryId()));
            }
        });
        data.setRecords(listCover(data.getRecords(), otherParam));
        return data;
    }

    @PostMapping("/updatePaperCategory")
    @Roles(Role.onlyLogin)
    @Transactional(rollbackFor = Exception.class)
    @Parameters({
            @Parameter(name = "ids", description = "ids", required = true),
            @Parameter(name = "categoryId", description = "考试分类id", required = true),
    })
    public Boolean updatePaperCategory(@RequestParam List<String> ids, @RequestParam Long categoryId) {
        //1、复制一套试卷，修改试卷分类，未修改试题的考试分类
        //2、逻辑删除原试卷，删除栏目配置下面的关系试卷，删除es试卷
        CategoryModel categoryModel = categoryService.getById(categoryId);
        List<PaperModel> paperModels = service.selectBatchIds(ids);
        List<PaperModel> newPaperModels = new ArrayList<>();
        for (PaperModel paperModel : paperModels) {
            PaperModel newPaper = new PaperModel();
            BeanUtil.copyProperties(paperModel, newPaper, "id", "createdTime", "createdBy", "modifyTime", "modifyBy");
            newPaper.setCategoryId(categoryId);
            newPaper.setOldCategoryId(paperModel.getCategoryId());
            newPaper.setIndustryId(categoryModel.getIndustryId());
            newPaper.setExamId(categoryModel.getExamId());
            newPaperModels.add(newPaper);
            //删除es试卷
            // paperEsService.delete(paperModel.getId());
        }
        // 新增新试卷
        boolean b = service.insertBatch(newPaperModels);
//        for (PaperModel newPaperModel : newPaperModels) {
//            // 新增新试卷到es
//            PaperEs paperEs = new PaperEs();
//            BeanUtil.copyProperties(newPaperModel, paperEs);
//            paperEsService.update(paperEs);
//        }
        // 删除栏目配置关系
        List<Long> exIds = exColumnConfigReService.selectList(Wrappers.<ExColumnConfigReModel>lambdaQuery()
                .in(ExColumnConfigReModel::getConfigId, ids)).parallelStream().map(BSIntEntity::getId).collect(Collectors.toList());
        if (!exIds.isEmpty()) {
            exColumnConfigReService.delete(exIds);
        }
        // 删除旧试卷
        return service.delete(ids);
    }

    @PutMapping("/hide-list")
    @Roles(Role.admin)
    @Operation(summary = "批量隐藏/取消隐藏")
    @Parameters({
            @Parameter(name = "ids", description = "ids", required = true),
            @Parameter(name = "isHide", description = "是否隐藏", required = true),
    })
    public Boolean batchHide(
            @RequestParam List<String> ids,
            @RequestParam Boolean isHide) {
        return service.batchHide(ids, isHide);
    }

    @DeleteMapping("/deleted-list")
    @Operation(summary = "批量删除试卷")
    @Parameters({
            @Parameter(name = "ids", description = "ids", required = true),
    })
    @Roles(Role.admin)
    public Boolean batchDelete(@RequestParam List<String> ids) {
        return service.delete(ids);
    }

    @GetMapping("/list-page")
    @Roles({Role.admin})
    public IPage<PaperModel> listPage(@ModelAttribute Page<PaperModel> page, @ModelAttribute PaperModel model, @NotNull JSONObject otherParam) {
        LambdaQueryWrapper<PaperModel> wrapper = baseWrapper(model, otherParam);
        wrapper.select(PaperModel::getId, PaperModel::getName, PaperModel::getSort);
        IPage<PaperModel> data = loadService().page(model.getCategoryId() == null ? page : service.pageProcessing(page), wrapper);
        data.setRecords(listCover(data.getRecords(), otherParam));
        return data;
    }

    @GetMapping("/list-more-page")
    @Roles({Role.admin})
    public IPage<PaperModel> listMorePage(@ModelAttribute Page<PaperModel> page, @ModelAttribute PaperModel model, @NotNull JSONObject otherParam) {
        //ColumnModel columnModel = columnService.morePaperByCategory(model.getCategoryId());
        Page<ExColumnConfigReModel> exColumnConfigReModelPage = new Page<>();
        exColumnConfigReModelPage.setCurrent(page.getCurrent());
        exColumnConfigReModelPage.setSize(page.getSize());
        Map<String, Object> param = MapUtil.<String, Object>builder()
                //.put("columnIds", Collections.singletonList(columnModel.getId()))
                .put("paperType", null != model.getPaperType() ? model.getPaperType().getValue() : null)
                .build();
        return this.loadService().paperByColumnIdPage(page, param);
    }

    @GetMapping("/paper-years")
    @Operation(summary = "获取栏目下的试卷年份")
    @Parameters({
            @Parameter(name = "columnId", description = "栏目id", required = true)
    })
    @Roles
    public List<Long> getColumnYears(@RequestParam Long category, String columnId) {
        var columnIds = StrUtil.isNotBlank(columnId) ? Collections.singletonList(columnId) : columnService.selectList(columnService.wrappers().eq(ColumnModel::getCategoryId, category)
                .eq(ColumnModel::getType, ColumnType.paperLibrary)
                .eq(ColumnModel::getShow, true)
        ).stream().map(BaseEntity::getId).toList();
        if (columnIds.isEmpty()) return Collections.emptyList();
        var ids = exColumnConfigReService.selectList(Wrappers.<ExColumnConfigReModel>lambdaQuery()
                        .select(ExColumnConfigReModel::getConfigId)
                        .in(ExColumnConfigReModel::getColumnId, columnIds))
                .stream().map(ExColumnConfigReModel::getConfigId).toList();
        if (ids.isEmpty()) return Collections.emptyList();
        return service.selectList(
                service.wrappers().select(PaperModel::getSourceYear)
                        .in(BaseEntity::getId, ids)
                        .groupBy(PaperModel::getSourceYear)
        ).stream().map(PaperModel::getSourceYear).filter(ObjectUtil::isNotEmpty).distinct().map(Long::valueOf).sorted(Comparator.reverseOrder()).toList();
    }

    @GetMapping("/paper-years-kaoyan")
    @Operation(summary = "获取栏目下的试卷年份")
    @Roles
    @ResultIgnore
    public List<String> getColumnYearsKaoyan(@RequestParam(required = false) List<Long> categoryIds) {
        List<PaperModel> paperModels =
                this.loadService().selectList(Wrappers.<PaperModel>lambdaQuery().
                        select(PaperModel::getSourceYear)
                        .isNotNull(PaperModel::getKaoyanCategoryId)
                        .ne(PaperModel::getKaoyanCategoryId, 0)
                        .eq(PaperModel::getPaperType, PaperType.trueTopic)
                        .in(null != categoryIds && !categoryIds.isEmpty(), PaperModel::getKaoyanCategoryId, categoryIds)
                        .groupBy(PaperModel::getSourceYear)
                        .orderByDesc(PaperModel::getSourceYear)
                );
        return paperModels.stream().map(PaperModel::getSourceYear).toList();
    }

    @GetMapping("/paper-category-kaoyan")
    @Operation(summary = "考研科目id")
    @Roles
    @ResultIgnore
    public List<Long> getPaperKaoyanCategory() {
        List<PaperModel> paperModels = this.loadService().selectList(Wrappers.<PaperModel>lambdaQuery().isNotNull(PaperModel::getKaoyanCategoryId).ne(PaperModel::getKaoyanCategoryId, 0).select(PaperModel::getKaoyanCategoryId).groupBy(PaperModel::getKaoyanCategoryId));
        return paperModels.parallelStream().map(PaperModel::getKaoyanCategoryId).toList();
    }

    @GetMapping("/client-detail")
    @Operation(summary = "客户端查看试卷详情")
    @Parameters({
            @Parameter(name = "id", description = "id", required = true),
    })
    @Roles
    public Map<String, Object> clientPaperDetail(@RequestParam String id) throws BizException {
        var p = service.getPaperInfo(id);
        return clientPaperDetail(userContext.currentUserId(), p, null);
    }

    @GetMapping("/paper-by-columnId")
    @Operation(summary = "根据栏目拉取试卷")
    @Parameters({
            @Parameter(name = "columnIds", description = "栏目id", required = true),
            @Parameter(name = "page", description = "分页模型"),
    })
    @Roles
    public IPage<Object> getPaperForColumn(@ModelAttribute Page<PaperModel> page,
                                           @RequestParam(required = true) List<String> columnIds,
                                           boolean countDetail
    ) {

        String userId = userContext.currentUserId();
        Map<String, Object> param = MapUtil.<String, Object>builder()
                .put("columnIds", columnIds).build();
        var rePage = this.loadService().paperByColumnIdPage(page, param);
        List<PaperModel> result = rePage.getRecords();
        var resultList = result.stream().filter(distinctByKey(BaseEntity::getId)).map(e -> {
            if (StrUtil.isBlank(userId) || !countDetail) {
                return e;
            }
            try {
                return clientPaperDetail(userId, e, columnIds.get(0));
            } catch (BizException ex) {
                throw new RuntimeException(ex);
            }
        }).toList();
        var pageResult = rePage.convert(Object.class::cast);
        return pageResult.setRecords(resultList);
    }

    public void excelExport() {
        List<PaperModel> paperModels = this.loadService().selectList(Wrappers.<PaperModel>lambdaQuery()
                .isNotNull(PaperModel::getKaoyanCategoryId)
                .eq(PaperModel::getPaperType, PaperType.trueTopic)
                .select(PaperModel::getId, PaperModel::getSort, PaperModel::getWatchTime, PaperModel::getSourceYear
                        , PaperModel::getCategoryId, PaperModel::getName, PaperModel::getPaperType, PaperModel::getKaoyanCategoryId, PaperModel::getStuCount
                )

        );
        paperModels.parallelStream().forEach(f -> {
            ExColumnConfigReModel model = exColumnConfigReService.selectFirst(Wrappers.<ExColumnConfigReModel>lambdaQuery().eq(ExColumnConfigReModel::getConfigId, f.getId()));
            if (null == model) {
            }

        });

    }

    @GetMapping("/paper-by-category-kaoyan")
    @Operation(summary = "根据科目拉取试卷")
    @Roles
    @ResultIgnore
    public IPage<Object> getPaperForKaoYan(@RequestParam Integer current,
                                           @RequestParam Integer size,
                                           @RequestParam(required = false) List<Long> categoryIds,
                                           @RequestParam(required = false) String year,
                                           @RequestParam(required = false) String userId

    ) {
        if (size > 999) {
            size = 999;

        }
        Page<PaperModel> page = new Page<>();
        page.setSize(size);
        page.setCurrent(current);
        IPage<PaperModel> rePage = this.loadService().page(page, Wrappers.<PaperModel>lambdaQuery()
                .eq(StrUtil.isNotBlank(year), PaperModel::getSourceYear, year)
                //.isNotNull(PaperModel::getKaoyanCategoryId)
                //.ne(PaperModel::getKaoyanCategoryId, 0)
                .in(null != categoryIds && !categoryIds.isEmpty(), PaperModel::getKaoyanCategoryId, categoryIds)
                //.eq(PaperModel::getPaperType, PaperType.trueTopic)
                .select(PaperModel::getId, PaperModel::getSort, PaperModel::getWatchTime, PaperModel::getSourceYear
                        , PaperModel::getCategoryId, PaperModel::getName, PaperModel::getPaperType, PaperModel::getKaoyanCategoryId, PaperModel::getStuCount
                )
                .orderByDesc(PaperModel::getSourceYear)
        );
        var result = rePage.getRecords();
        var resultList = result.stream().filter(distinctByKey(BaseEntity::getId)).map(e -> {
            Long categoryId = e.getCategoryId();
            CategoryModel categoryModel = categoryService.getById(categoryId);
            e.setExamId(categoryModel.getExamId());
            e.setIndustryId(categoryModel.getIndustryId());
            ExColumnConfigReModel model = exColumnConfigReService.selectFirst(Wrappers.<ExColumnConfigReModel>lambdaQuery().eq(ExColumnConfigReModel::getConfigId, e.getId()));
            if (null != model) {
                e.setColumnId(model.getColumnId());
            }
            if (StrUtil.isBlank(userId)) {
                return e;
            }
            try {
                return clientPaperDetail(userId, e, null);
            } catch (BizException ex) {
                throw new RuntimeException(ex);
            }
        }).toList();
        var pageResult = rePage.convert(Object.class::cast);
        return pageResult.setRecords(resultList);

    }

    private Map<String, Object> clientPaperDetail(String userId, PaperModel e, String columnId) throws BizException {
        var map = BeanUtil.beanToMap(e);
        if (StrUtil.isNotBlank(userId)) {
            var list = paperRecordsService.questionRecord(userId, PaperRecordType.paperLibrary, e.getId());
            var working = list.stream().filter(v -> !v.getHaveFinish()).findFirst().orElse(null);
            // 试卷做题次数
            map.put("count", !list.isEmpty() ? (null != list.get(0).getCompleteCount() ? list.get(0).getCompleteCount() : 0) : 0);
            // 试卷做题状态
            map.put("working", working != null);
            map.put("recordId", working != null ? working.getId() : null);
            if (map.get("free") != null)
                map.put("free", !((Boolean) map.get("free")) ? columnService.currentHaveAuth(null, null, userId, null, columnId, null) : map.get("free"));
        }
        return map;
    }

    @Override
    protected LambdaQueryWrapper<PaperModel> baseWrapper(PaperModel model, JSONObject otherParam) {
        return Wrappers.lambdaQuery(model.clearEmptyStringField("name", "categoryId"))
                .select(PaperModel::getId, PaperModel::getSort, PaperModel::getWatchTime, PaperModel::getSourceYear, PaperModel::getCategoryId, PaperModel::getName, PaperModel::getPaperType, PaperModel::getKaoyanCategoryId, PaperModel::getStuCount).like(StringUtil.isNotBlank(model.getName()), PaperModel::getName, model.getName())
                .eq(model.getCategoryId() != null, PaperModel::getCategoryId, model.getCategoryId()).or()
                .eq(model.getCategoryId() != null, PaperModel::getHighEduId, model.getCategoryId())
                .orderByDesc(PaperModel::getCreatedTime);
    }

    @GetMapping("exportPaper")
    @Operation(summary = "下载试卷")
    @Parameters({
            @Parameter(name = "paperRecordsId", description = "集合id", required = true),
            @Parameter(name = "answerDesc", description = "是否带解析"),
    })
    @RateLimiterApi(namespace = "exportPaper", maxRate = 20, millisecond = 1000 * 60)
    public String exportPaper(@RequestParam("paperRecordsId") String paperRecordsId, @RequestParam(required = false) String paperId, @RequestParam(value = "answerDesc", defaultValue = "false") Boolean answerDesc) throws IOException, BizException {
        if (null == paperRecordsId) {
            throw new BizRuntimeException("参数错误");
        }
        URL url = service.exportPaper(paperRecordsId, paperId, answerDesc);
        if (null == url) {
            throw new BizRuntimeException();
        }
        return url.toString().replaceFirst("http", "https");
    }

//    @GetMapping("get-info-index")
//    @Operation(summary = "首页搜索试卷")
//    @Parameters({
//            @Parameter(name = "keyword", description = "搜索词"),
//            @Parameter(name = "type", description = "试卷类型，0历年 1模拟"),
//            @Parameter(name = "year", description = "所属年份"),
//            @Parameter(name = "sourceYear", description = "是否按照年份排序"),
//    })
//    @Roles
//    public Page<PaperModel> getInfoIndex(@ModelAttribute Page<PaperModel> page, @RequestParam String keyword, @RequestParam(required = false) Integer type, @RequestParam(required = false) String year, @RequestParam(required = false) String examId, @RequestParam(required = false) String industryId, @RequestParam(defaultValue = "false") Boolean sourceYear) throws IOException {
//        if (Sensitive.isSensitive(keyword)) {
//            return page;
//        }
//        Map<String, Object> mustMap = MapUtil.<String, Object>builder()
//                .put("name", keyword)
//                .build();
//        Map<String, Map<String, Object>> shouldMap = new HashMap<>();
//        //存试题的时候需要把examId 跟industryId 存入 es   或者 存试题表的categoryId，搜索是根据考试找到多个科目再来搜索。
//        Map<String, Object> filterMap = new HashMap<>();
//        if (StringUtil.isNotBlank(examId)) {
//            filterMap.put("examId", examId);
//        }
//        if (StringUtil.isNotBlank(industryId)) {
//            filterMap.put("industryId", industryId);
//        }
//        if (type != null) {
//            filterMap.put("paperType", type.intValue());
//        }
//        if (StrUtil.isNotBlank(year)) {
//            filterMap.put("sourceYear", year);
//        }
//        Map<String, SortOrder> sort = new HashMap<>();
//        if (sourceYear) {
//            sort.put("sourceYear", SortOrder.DESC);
//        }
//        ArrayList<String> existColumnIds = new ArrayList<>();
//        existColumnIds.add("columnId");
//        Map<String, Object> resMap = esSearchUtil.esByConditions(page, shouldMap, mustMap, filterMap, existColumnIds, sort, "vip-vers7_paper", service, "name");
//
//        Map<String, Map<String, String>> replaceMap = (Map<String, Map<String, String>>) resMap.get("replaceMap");
//
//        Page<PaperModel> resPage = (Page<PaperModel>) resMap.get("page");
//
//        return resPage.setRecords(resPage.getRecords().stream().filter(ObjectUtil::isNotNull).peek(r -> {
//            Map<String, String> map = replaceMap.get(r.getId());
//            if (map != null) {
//                if (StringUtil.isNotBlank(map.get("name"))) {
//                    r.setName(replaceMap.get(r.getId()).get("name"));
//                }
//            }
//            ExColumnConfigReModel exColumnConfigReModel = exColumnConfigReService.selectFirst(Wrappers.<ExColumnConfigReModel>lambdaQuery()
//                    .eq(ExColumnConfigReModel::getConfigId, r.getId()));
//            r.setColumnId(exColumnConfigReModel != null ? exColumnConfigReModel.getColumnId() : null);
//            CategoryModel categoryModel = categoryService.getById(r.getCategoryId());
//            ExamModel examModel = examService.getById(categoryModel.getExamId());
//            IndustryModel industryModel = industryService.getById(categoryModel.getIndustryId());
//            r.setExamName(examModel.getName());
//            r.setExamId(examModel.getId());
//            r.setCategoryName(categoryModel.getName());
//            r.setIndustryId(industryModel.getId());
//            r.setIndustryName(industryModel.getName());
//        }).toList());
//    }

    @PutMapping("add-frequency")
    @Operation(summary = "增加下载次数、查看次数")
    @Parameters({
            @Parameter(name = "id", description = "试卷id")})
    @Roles
    public void addFrequency(@RequestParam String id) {
        loadService().update(null, Wrappers.<PaperModel>lambdaUpdate().eq(BaseEntity::getId, id).setSql("watch_time=watch_time+1"));
    }

    @PostMapping("/update")
    @Transactional(rollbackFor = Exception.class)
    public PaperModel add(@RequestBody PaperModel entity) {
        PaperModel paperModel = service.insert(entity);
        if (StrUtil.isNotBlank(entity.getColumnId())) {
            ExColumnConfigReModel exColumnConfigReModel = new ExColumnConfigReModel();
            exColumnConfigReModel.setConfigId(paperModel.getId());
            exColumnConfigReModel.setIsFree(true);
            exColumnConfigReModel.setColumnId(entity.getColumnId());
            exColumnConfigReService.insert(exColumnConfigReModel);
        }
        //paperEsService.update(service.modelTransEs(paperModel, null));
        return paperModel;
    }


    @PostMapping("/addPaperWithFile")
    @Transactional(rollbackFor = Exception.class)
    public PaperModel addPaperWithFile(@RequestParam(name = "paper") String var1, @RequestPart MultipartFile file) throws IOException {
//        formData消息转换器无法转换

        JSONObject jsonObject = JSONUtil.parseObj(var1);
        String columnId = (String) jsonObject.get("columnId");
        Long categoryId = Long.valueOf((Integer) jsonObject.get("categoryId"));

//        JSONObject jsonObject1 = JSONUtil.parseObj(var2);
//        Integer knowledgeLevel =(Integer) jsonObject1.get("knowledgeLevel");

        PaperModel entity = new PaperModel();


        entity.setColumnId(columnId);
        entity.setCategoryId(categoryId);
        entity.setName((String) jsonObject.get("name"));
        entity.setSort((Integer) jsonObject.get("sort"));
        entity.setExamTime((Integer) jsonObject.get("examTime"));
//        entity.setIndustryId((Integer) jsonObject.get("sort"));
        entity.setPaperType(PaperType.valueOf((String) jsonObject.get("paperType")));
        entity.setPassScore((Integer) jsonObject.get("passScore"));
        entity.setRemark((String) jsonObject.get("remark"));
        entity.setSourceYear((String) jsonObject.get("sourceYear"));
        entity.setTotalScore((Integer) jsonObject.get("totalScore"));
        entity.setIsHide(((Integer) jsonObject.get("isHide")).intValue() == 0 ? false : true);
        entity.setIntegrityState((Integer) jsonObject.get("integrityState"));



        Map<String,Object> params=new HashMap<>();
        params.put("knowledgeLevel", jsonObject.get("knowledgeLevel"));
        params.put("categoryId",categoryId);
        Map<String,Object> resultMap=wordToHtmlInOrder.uploadFileToQuestion(file,params);


        List<QuestionCollectionBlockItem> contentList=(List<QuestionCollectionBlockItem>) resultMap.get("contentList");
        List<QuestionModel> questionModels=(List<QuestionModel>) resultMap.get("questionModels");
        CategoryModel category=(CategoryModel) resultMap.get("category");
        entity.setExamId(category.getExamId());
        entity.setIndustryId(category.getIndustryId());


        List<String> questionIds=(List<String>) resultMap.get("questionIds");
        entity.setQcount(questionIds.size());

        entity.setContent(contentList);
        PaperModel paperModel = service.insert(entity);
        if (StrUtil.isNotBlank(entity.getColumnId())) {
            ExColumnConfigReModel exColumnConfigReModel = new ExColumnConfigReModel();
            exColumnConfigReModel.setConfigId(paperModel.getId());
            exColumnConfigReModel.setIsFree(true);
            exColumnConfigReModel.setColumnId(entity.getColumnId());
            exColumnConfigReService.insert(exColumnConfigReModel);
        }
        //paperEsService.update(service.modelTransEs(paperModel, null));
        return paperModel;
    }


    @PutMapping("/update")
    public PaperModel update(@RequestBody PaperModel entity) {
        //paperEsService.update(service.modelTransEs(entity, null));
        return loadService().simpleUpdate(entity);
    }

    @DeleteMapping("/delete")
    public Boolean delete(@RequestParam String id) {
        // paperEsService.delete(id);
        return loadService().delete(id);
    }

//    @GetMapping("/FilterCondition")
//    @Operation(description = "获取查询字段")
//    @Parameters({
//            @Parameter(name = "industryId", description = "行业id"),
//            @Parameter(name = "examId", description = "考试id")
//    })
//    @Roles
//    public Map<String, Object> getFilterCondition(@RequestParam(required = false) String industryId, @RequestParam(required = false) String examId) {
//        return paperEsService.getFilterCondition(industryId, examId);
//    }

//    @PostMapping("/syncES")
//    @Operation(description = "同步试卷到es")
//    public void syncES() {
//        var allCategory = categoryService.selectList(categoryService.wrappers().select(CategoryModel::getId));
//        var redisKey = "SYNC_PAPER_ES";
//        var redisStatus = redisTemplate.opsForValue().get(redisKey);
//        if (redisStatus != null) {
//            throw new BizRuntimeException(String.format("同步中，已完成%s个科目。总%d个科目", redisStatus, allCategory.size()));
//        }
//        redisTemplate.opsForValue().set(redisKey, 0, Duration.ofMinutes(20));
//        int i = 0;
//        for (var category : allCategory) {
//            var papers = service.selectList(service.wrappers().eq(PaperModel::getCategoryId, category.getId()));
//            for (var j = 0; j < papers.size(); j += 100) {
//                var qs1 = papers.subList(j, Math.min(j + 100, papers.size()));
//                paperEsService.batchUpdate(qs1.stream().map(model -> service.modelTransEs(model, category)).toList());
//            }
//            i++;
//            redisTemplate.opsForValue().set(redisKey, i, Duration.ofMinutes(20));
//        }
//    }

    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/generate-paper")
    public void specialConditionResult(@RequestParam Long categoryId, @RequestParam Long questionSourceCategoryId, @ModelAttribute("condition") SpecialConditionVo condition, @RequestParam(defaultValue = "1") Integer count, String name, String columnName, @RequestParam(required = false) List<String> ids, @RequestParam(defaultValue = "false") Boolean isScattered) {
        ColumnModel columnModel = columnService.selectFirst(Wrappers.<ColumnModel>lambdaQuery().eq(ColumnModel::getType, ColumnType.paperLibrary).eq(ColumnModel::getCategoryId, categoryId).eq(ColumnModel::getName, columnName));
        String columnId;
        if (null == columnModel) {
            var column = new ColumnModel();
            column.setType(ColumnType.paperLibrary);
            column.setName(columnName);
            column.setCategoryId(categoryId);
            columnService.insert(column);
            columnId = column.getId();
        } else {
            columnId = columnModel.getId();
        }
        List<String> inIds = null;
        if (null != ids && !ids.isEmpty()) {
            inIds = chapterService.getQuestionIdsByChapter(ids);
        }
        if (isScattered) {
            inIds = questionService.getScatteredQuestion(categoryId, false);
        }
        for (var i = 0; i < count; i++) {
            var paperName = count == 1 ? name : name + ConvertUtil.toChinese(String.valueOf(i + 1));
            service.categoryGeneratePaper(categoryId, questionSourceCategoryId, condition, paperName, columnId, columnName, inIds, isScattered);
        }
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
}
